#ifndef _PARSER_H_
#define _PARSER_H_

/**********************************************************************
 * Parser.h
 * 
 * Descripcion:
 * Implementa métodos relacionados con el parseo.Desde generar tipos de
 * datos a partir de strings, casteos, etcs
 **********************************************************************/ 
#include <string>
#include <sstream>
#include "tipo_dato.h"
#include "tipo_struct.h"
#include "tipo_int.h"
#include "tipo_string.h"
#include "tipo_colec.h"
#include "funcProcAtomIng.h"
#include "funcProcStructIng.h"
#include "excep_parser_sintaxis.h"
#include "excep_sintaxis_estructura_crear.h"

class Parser{
	
	public:
		/*
		 * Devuelve un tipo de dato a partir de la cadena pasada por
		 * parametro. 
		 * En caso de no existir, lanza una excepcion
		 */ 
		static TipoDato *  crear_tipo_desde_cadena(std::string &tipo) throw(ExcepSintaxisParser);
		
		/*
		 * Compara el nombre_operacion con el correspondiente pasado por parametro
		 * Si coinciden devuelve true y quita de param este valor.
		 * Remueve todos los espacios en blanco.
		 * De lo contrario devuelve false, y param no se modifica, en este caso no
		 * se encontro ninguna operacion valida.   
		 */
		static bool procesar_nombre_operacion(std::string &param, std::string &nombre_operacion);
		
		/*
		 * Separa la expresion mandada como param en campos, segun si son ints, strings o estructurados.
		 * Devuelve los campos resultantes en un vector de strings.
		 */
		static std::vector<std::string> obtener_campos(std::string cadena);
		
		/*
		 * Separa una cadena en varias segun un delimitador.
		 * Devuelve las cadenas resultantes en un vector de strings.
		 */
		static std::vector<std::string> split_parametros(std::string cadena,char delimitador);
		
		/*
		 * Valida si una cadena es un dato de tipo string. Esto ocurre si respeta la forma
		 * 'XXX'.
		 * Devuelve true si cumple esta condicion, false en caso contrario.
		 */ 
		static bool es_string(const std::string &cadena);
		
		/*
		 * Convierte un string a int y lo guarda en campo. En caso de 
		 * no poder realizarse devuelve false, en caso exitoso, true.
		 */ 
		 static bool convertir_a_int(std::string &dato,int& campo);
		   
		/*
		 * Dada una expresion compuesta de datos atomicos separados por ',' devuelve
		 * un vector con los datos ya convertidos a su tipo de dato correspondiente.
		 * Lanza una excepcion del tipo ExcepSintaxisParser si hay un error de conversion de tipos.
		 */          
		 static std::vector<TipoDato *> obtener_datos_atomicos (const std::string &expr)
		  												throw (ExcepSintaxisParser);
								
		/*
		 * Procesar datos secundarios: Dados un struct que simboliza un registro,
		 * y un string con los datos secundarios separados por comas y encerrados por [] 
		 * pasados por parametros, parsea la linea y llena el registro de forma correcta.
		 * Recibe un functor que indica como procesar los datos atomicos y otro
		 * para los structs.
		 * Si hay errores de sintaxis en el parseo de los datos arroja una excepcion del tipo
		 * ExcepSintaxisParser.
		 */
		static void procesar_datos_secundarios(const std::string &expr, TipoStruct* registro,
										Funcion &procesar_atom, Funcion &procesar_struct)
										throw (ExcepSintaxisParser);
		
		/*
		 * Procesar valor: dado un string pasado por parametro, verifica que Tipo de Dato es
		 * si es un int devuelve un TipoInt*, si es un string devuelve un TipoString*
		 * ambos son TipoDato*.
		 * Si hay errores de sintaxis en el parseo de los datos arroja una excepcion del tipo
		 * ExcepSintaxisParser.
		 */								
		static TipoDato* procesar_valor(std::string aux)throw (ExcepSintaxisParser);
		
		/*
		 * Procesar Ingreso: Dados un string pasado por param que contiene la cadena con los datos
		 * secundarios del ingreso y un registro vacio, intenta parsear el ingreso y llenar el registro
		 * con los datos parseados. Si hay un error de sintaxis arroja una excep.
		 */
		static void procesar_ingreso(std::string datos_sec, TipoStruct* reg) throw (ExcepSintaxisParser);
		
		/*
		 * Procesar Nombre: Dado un nombre con formato 'nombre', devuelve lo que esta entre '' en un nuevo
		 * string. Si hay un error de sintaxis en el formato, arroja una excep de tipo sintaxis parser.
		 */
		static std::string procesar_nombre(std::string nombre) throw (ExcepSintaxisParser);
		
		/*
		 * Procesar campo impar: dada una expresion devuelve un TipoInt*, un TipoString* o TipoColec*
		 * dependiendo del tipo de dato de la misma, si es que no existen errores de parsing.
		 * En caso contrario arroja una excepcion.
		 * Necesita el reg base del archivo en el cual se esta efectuando la operacion, y el numero de campo.
		 */
		static TipoDato* procesar_campo_impar(std::string expresion, unsigned int num_campo, TipoStruct* reg_base) 
																	throw (ExcepSintaxisParser);
	
		/*
		 * Revisa que no hayan dos comas seguidas ni una coma despues de 
		 * un [ o antes del mismo.
		 */ 
		static void revisar_comas(const std::string &expresion) throw (ExcepSintaxisParser);

		/*
		 * Lanza una excepcion si hay un punto y coma dentro de un struct
		 */ 
		static void revisar_pcoma_dentro_struct(std::string &expresion) throw (ExcepSintaxisParser);
	
		/*
		 * Revisa que no hayan un campo struct separado de otros sin una coma
		 */
		 static void estan_separados_bien(const std::string& cadena) throw (ExcepSintaxisParser);		
	private:
	
		/*
		 * Metodo de uso interno que dado un reg, intenta llenar todos los campos obligatorios vacios
		 * con los optativos llenos cuando se pueda. 
		 */
		static void reestructurar(TipoStruct* reg);
		
		/*
		 * Metodo de uso interno que dada una cadena elimina los espacios en blanco, salvo que esten dentro
		 * de '.
		 */
		static void trim(std::string &cadena);
			
};

#endif
